Expose rustc cfg values to build scripts
authorAlex Crichton <alex@alexcrichton.com>
Mon, 31 Oct 2016 23:20:38 +0000 (16:20 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 2 Nov 2016 23:24:32 +0000 (16:24 -0700)
This commit is Cargo's portion of the implementation of [RFC 1721] where it will
expose values printed by `rustc --print cfg` to build scripts.

[RFC 1721]: https://github.com/rust-lang/rfcs/blob/master/text/1721-crt-static.md

This will in turn be used to communicate features like `-C
target-feature=+crt-static` which can be used to compile objects for statically
linking against the msvcrt on MSVC.

src/cargo/ops/cargo_rustc/context.rs
src/cargo/ops/cargo_rustc/custom_build.rs
tests/build-script.rs

index 59aa170212c31b6b48d95e33074ed24ca8a6f417..4e0cf00db6af268a54c9906cdaa94e6d295e6501 100644 (file)
@@ -678,6 +678,15 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
         self.target_config(kind).ar.as_ref().map(|s| s.as_ref())
     }
 
+    /// Get the list of cfg printed out from the compiler for the specified kind
+    pub fn cfg(&self, kind: Kind) -> &[Cfg] {
+        let info = match kind {
+            Kind::Host => &self.host_info,
+            Kind::Target => &self.target_info,
+        };
+        info.cfg.as_ref().map(|s| &s[..]).unwrap_or(&[])
+    }
+
     /// Get the target configuration for a particular host or target
     fn target_config(&self, kind: Kind) -> &TargetConfig {
         match kind {
index 6a324a378a1a46351b7279faabd5546a6c6e7ff2..54c688134be57efea6940311ade8b6728f648187 100644 (file)
@@ -5,7 +5,7 @@ use std::str;
 use std::sync::{Mutex, Arc};
 
 use core::PackageId;
-use util::{CargoResult, Human, Freshness};
+use util::{CargoResult, Human, Freshness, Cfg};
 use util::{internal, ChainError, profile, paths};
 
 use super::job::Work;
@@ -124,6 +124,26 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>)
         }
     }
 
+    let mut cfg_map = HashMap::new();
+    for cfg in cx.cfg(unit.kind) {
+        match *cfg {
+            Cfg::Name(ref n) => { cfg_map.insert(n.clone(), None); }
+            Cfg::KeyPair(ref k, ref v) => {
+                match *cfg_map.entry(k.clone()).or_insert(Some(Vec::new())) {
+                    Some(ref mut values) => values.push(v.clone()),
+                    None => { /* ... */ }
+                }
+            }
+        }
+    }
+    for (k, v) in cfg_map {
+        let k = format!("CARGO_CFG_{}", super::envify(&k));
+        match v {
+            Some(list) => { cmd.env(&k, list.join(",")); }
+            None => { cmd.env(&k, ""); }
+        }
+    }
+
     // Gather the set of native dependencies that this package has along with
     // some other variables to close over.
     //
index e0669311039323f92a550c3a6138fb05ad03cda3..18fca1ea7105777a25b68e61794517dd4a3864c0 100644 (file)
@@ -2259,3 +2259,30 @@ fn rustc_and_rustdoc_set_correctly() {
     assert_that(build.cargo_process("bench"),
                 execs().with_status(0));
 }
+
+#[test]
+fn cfg_env_vars_available() {
+    let build = project("builder")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "builder"
+            version = "0.0.1"
+            authors = []
+            build = "build.rs"
+        "#)
+        .file("src/lib.rs", "")
+        .file("build.rs", r#"
+            use std::env;
+
+            fn main() {
+                let fam = env::var("CARGO_CFG_TARGET_FAMILY").unwrap();
+                if cfg!(unix) {
+                    assert_eq!(fam, "unix");
+                } else {
+                    assert_eq!(fam, "windows");
+                }
+            }
+        "#);
+    assert_that(build.cargo_process("bench"),
+                execs().with_status(0));
+}